{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "#load \"..\\Extension\\LoadBaseTool.csx\"\n",
    "using BaseTool;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [],
   "source": [
    "List<int> numbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 筛选数据\n",
    "筛选所有的偶数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2, 4, 6, 8, 10\r\n"
     ]
    }
   ],
   "source": [
    "numbers.Where( n => n % 2 == 0 ).Dump();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 选择数据进行操作\n",
    "所有的数乘以2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2, 4, 6, 8, 10, 12, 14, 16, 18, 20\r\n"
     ]
    }
   ],
   "source": [
    "numbers.Select(n => n * 2 ).Dump();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 方法链和查询语句\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6, 7, 8, 9, 10\n",
      "6, 7, 8, 9, 10\n"
     ]
    }
   ],
   "source": [
    "numbers.Where(n => n > 5).Select(n=>n).Dump();\n",
    "(from item in numbers where item > 5 select item).Dump();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## orderby 和 descending 进行排序\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10, 9, 8, 7, 6, 5, 4, 3, 2, 1\r\n"
     ]
    }
   ],
   "source": [
    "(from item in numbers orderby item descending select item).Dump();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## ThenBy / ThenByDescending: 用于在现有排序的基础上进行次级排序\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## SelectMany 用于将嵌套的集合展平，并选择元素。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fruit, Organic, Food, Bakery\n",
      "{ Name = Apple, category = Fruit }, { Name = Apple, category = Organic }, { Name = Bread, category = Food }, { Name = Bread, category = Bakery }\n"
     ]
    }
   ],
   "source": [
    "public class Product\n",
    "{\n",
    "    public string Name { get; set; }\n",
    "    public List<string> Categories { get; set; }\n",
    "}\n",
    "\n",
    "var products = new List<Product>\n",
    "{\n",
    "    new Product \n",
    "    { \n",
    "        Name = \"Apple\", \n",
    "        Categories = new List<string> { \"Fruit\", \"Organic\" } \n",
    "    },\n",
    "    new Product \n",
    "    { \n",
    "        Name = \"Bread\", \n",
    "        Categories = new List<string> { \"Food\", \"Bakery\" } \n",
    "    }\n",
    "};\n",
    "\n",
    "products.SelectMany(p => p.Categories).Dump();\n",
    "(from product in products\n",
    "from category in product.Categories \n",
    "select new { product.Name, category }).Dump();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## GroupBy: 用于将数据源中的元素按某个键进行分组。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Age: 25, People: Submission#28+Person, Submission#28+Person\n",
      "Age: 30, People: Submission#28+Person\n",
      "Age: 20, People: Submission#28+Person\n"
     ]
    }
   ],
   "source": [
    "public class Person\n",
    "{\n",
    "    public string Name { get; set; }\n",
    "    public int Age { get; set; }\n",
    "}\n",
    "\n",
    "\n",
    "var people = new List<Person>\n",
    "{\n",
    "    new Person { Name = \"Alice\", Age = 25 },\n",
    "    new Person { Name = \"Bob\", Age = 25 },\n",
    "    new Person { Name = \"Charlie\", Age = 30 },\n",
    "    new Person { Name = \"David\", Age = 20 }\n",
    "};\n",
    "\n",
    "var ageGroups = people.GroupBy(p => p.Age);\n",
    "\n",
    "foreach (var group in ageGroups)\n",
    "{\n",
    "    Console.WriteLine($\"Age: {group.Key}, People: {string.Join(\", \", group)}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Join / GroupJoin: 用于基于键值将两个序列连接起来。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OrderID: 10, CustomerID: 1, Customer: Alice\n",
      "OrderID: 20, CustomerID: 2, Customer: Bob\n"
     ]
    }
   ],
   "source": [
    "public class Order\n",
    "{\n",
    "    public int OrderId { get; set; }\n",
    "    public int CustomerId { get; set; }\n",
    "}\n",
    "\n",
    "public class Customer\n",
    "{\n",
    "    public int Id { get; set; }\n",
    "    public string Name { get; set; }\n",
    "}\n",
    "\n",
    "var orders = new List<Order>\n",
    "{\n",
    "    new Order { OrderId = 10, CustomerId = 1 },\n",
    "    new Order { OrderId = 20, CustomerId = 2 },\n",
    "    // Order with no matching customer\n",
    "    new Order { OrderId = 30, CustomerId = 3 }\n",
    "};\n",
    "\n",
    "var customers = new List<Customer>\n",
    "{\n",
    "    new Customer { Id = 1, Name = \"Alice\" },\n",
    "    new Customer { Id = 2, Name = \"Bob\" }\n",
    "};\n",
    "\n",
    "// 连接orders列表和customers列表，orders的CustomerId与customers的Id相匹配\n",
    "\n",
    "var orderDetails = orders.Join(\n",
    "                            customers, \n",
    "                            o => o.CustomerId, \n",
    "                            c => c.Id, \n",
    "                            (o, c) => new { Order = o, CustomerName = c.Name });\n",
    "\n",
    "foreach (var detail in orderDetails)\n",
    "{\n",
    "    Console.WriteLine($\"OrderID: {detail.Order.OrderId}, CustomerID: {detail.Order.CustomerId}, Customer: {detail.CustomerName}\");\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aggregate: 用于将数据源中的所有元素聚合成一个单一的结果。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ StudentName = Alice, Grade = 90 }, { StudentName = Bob, Grade = 85 }, { StudentName = Charlie, Grade = 95 }\n",
      "Age: 20\n",
      "Name: Alice\n",
      "\n",
      "Age: 22\n",
      "Name: Bob\n",
      "\n",
      "Age: 21\n",
      "Name: Charlie\n",
      "\n",
      "Oldest Student: Bob\n"
     ]
    }
   ],
   "source": [
    "class Student\n",
    "{\n",
    "    public string Name { get; set; }\n",
    "    public int Age { get; set; }\n",
    "}\n",
    "\n",
    "class Grade\n",
    "{\n",
    "    public string StudentName { get; set; }\n",
    "    public int Score { get; set; }\n",
    "}\n",
    "\n",
    "var students = new List<Student>\n",
    "{\n",
    "    new Student { Name = \"Alice\", Age = 20 },\n",
    "    new Student { Name = \"Bob\", Age = 22 },\n",
    "    new Student { Name = \"Charlie\", Age = 21 }\n",
    "};\n",
    "\n",
    "var grades = new List<Grade>\n",
    "{\n",
    "    new Grade { StudentName = \"Alice\", Score = 90 },\n",
    "    new Grade { StudentName = \"Bob\", Score = 85 },\n",
    "    new Grade { StudentName = \"Charlie\", Score = 95 }\n",
    "};\n",
    "\n",
    "var result = students.Join(grades, \n",
    "                            s => s.Name, \n",
    "                            g => g.StudentName, \n",
    "                            (s, g) => new { StudentName = s.Name, Grade = g.Score });\n",
    "result.Dump(); // 连接两个序列并返回一个新的序列，其中包含每个学生的成绩\n",
    "\n",
    "var groupedResult = students.GroupBy(s => s.Age);\n",
    "foreach (var group in groupedResult)\n",
    "{\n",
    "        Console.WriteLine($\"Age: {group.Key}\");\n",
    "        foreach (var student in group)\n",
    "        {\n",
    "            Console.WriteLine($\"Name: {student.Name}\");\n",
    "        }\n",
    "        Console.WriteLine();\n",
    "}\n",
    "\n",
    "var aggregatedResult = students.Aggregate((a, b) => a.Age > b.Age ? a : b);\n",
    "Console.WriteLine($\"Oldest Student: {aggregatedResult.Name}\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Any / All: 用于检查数据源中是否存在满足条件的元素（Any），或所有元素是否都满足条件（All）。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Contains: 用于检查数据源是否包含特定的元素。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DefaultIfEmpty: 用于确保即使数据源为空也能返回一个空的序列。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Distinct: 用于返回数据源中的唯一元素。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1, 2, 3, 4, 5, 6, 7, 8, 9, 10\n",
      "True\n",
      "False\n",
      "True\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "List<int> numbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 2, 2, 2 ];\n",
    "numbers.Distinct().Dump(); // 返回唯一元素\n",
    "numbers.Contains(3).Dump(); // 检查数据源是否包含特定的元素\n",
    "numbers.Any(n => n > 10).Dump(); // 检查是否存在满足条件的元素\n",
    "numbers.All(n => n > 0).Dump(); // 检查所有元素是否都满足条件\n",
    "numbers.Where(n=>n > 10).DefaultIfEmpty(1).Dump(); // 即使数据源为空也能返回一个空的序列"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## First / FirstOrDefault: 用于获取数据源中的第一个元素或第一个满足条件的元素，如果没有找到则返回默认值。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Last / LastOrDefault: 类似于 First，但用于获取最后一个元素。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Count 获取数据源中的元素数量。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "6\n",
      "10\n",
      "10\n",
      "10\n"
     ]
    }
   ],
   "source": [
    "List<int> numbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];\n",
    "numbers.First().Dump(); // 获取第一个元素\n",
    "numbers.First(n => n > 5).Dump(); // 获取第一个满足条件的元素\n",
    "numbers.Last().Dump(); // 获取最后一个元素\n",
    "numbers.Last(n => n > 5).Dump(); // 获取最后一个满足条件的元素\n",
    "numbers.Count().Dump(); // 获取元素数量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Skip / SkipWhile: 用于跳过数据源中的前 N 个元素或跳过满足条件的元素。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Take / TakeWhile: 用于获取数据源中的前 N 个元素或获取满足条件的元素。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4, 5, 6, 7, 8, 9, 10\n",
      "4, 5, 6, 7, 8, 9, 10\n",
      "1, 2, 3\n",
      "1, 2, 3\n"
     ]
    }
   ],
   "source": [
    "List<int> numbers = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];\n",
    "numbers.Skip(3).Dump(); // 跳过前3个元素\n",
    "numbers.SkipWhile(n => n < 4).Dump(); // 跳过满足条件的元素\n",
    "numbers.Take(3).Dump(); // 获取前3个元素\n",
    "numbers.TakeWhile(n => n < 4).Dump(); // 获取满足条件的元素"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Union / Intersect / Except: 用于集合操作，返回两个序列的并集、交集或差集\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14\n",
      "5, 6, 7, 8, 9, 10\n",
      "1, 2, 3, 4\n"
     ]
    }
   ],
   "source": [
    "List<int> numbers1 = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];\n",
    "List<int> numbers2 = [ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ];\n",
    "numbers1.Union(numbers2).Dump();\n",
    "numbers1.Intersect(numbers2).Dump();\n",
    "numbers1.Except(numbers2).Dump();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## let 关键字\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ a = 3, b = 9, sum = 12 }\n",
      "{ a = 4, b = 8, sum = 12 }\n",
      "{ a = 5, b = 7, sum = 12 }\n",
      "{ a = 6, b = 6, sum = 12 }\n"
     ]
    }
   ],
   "source": [
    "\n",
    "var groupA = new[] { 3, 4, 5, 6 };\n",
    "var groupB = new[] { 6, 7, 8, 9 };\n",
    "var someInts = from a in groupA\n",
    "                from b in groupB\n",
    "                let sum = a + b         //在新的变量中保存结果\n",
    "                where sum == 12\n",
    "                select new { a, b, sum };\n",
    "foreach (var a in someInts)\n",
    "{\n",
    "    Console.WriteLine(a);\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\r\n"
     ]
    }
   ],
   "source": [
    "var groupA = new[] { 3, 4, 5, 6 };\n",
    "var groupB = new[] { 6, 7, 8, 9 };\n",
    "var someInts = from a in groupA\n",
    "                join b in groupB on a equals b\n",
    "                into groupAandB\n",
    "                from c in groupAandB\n",
    "                select c;\n",
    "foreach (var a in someInts)\n",
    "{\n",
    "    Console.WriteLine(a);\t// 6\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "11\n"
     ]
    }
   ],
   "source": [
    "List<int> _list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };\n",
    "\n",
    "var _num1 = _list.FirstOrDefault(n => n == 11);\n",
    "_num1.Dump();\n",
    "\n",
    "var _num2 = _list.FirstOrDefault(n => n == 11, 11);\n",
    "_num2.Dump(); // 11\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## FirstOrDefault"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "name: 李四, age: 20\n",
      "\n",
      "True\n",
      "name: 默认, age: 20\n"
     ]
    }
   ],
   "source": [
    "class student\n",
    "{\n",
    "    public string name { get; set; }\n",
    "    public int age { get; set; }\n",
    "\n",
    "    override public string ToString() => $\"name: {name}, age: {age}\";\n",
    "}\n",
    "\n",
    "List<student> _list = new List<student>();\n",
    "_list.Add(new student { name = \"张三\", age = 18 });\n",
    "_list.Add(new student { name = \"李四\", age = 20 });\n",
    "_list.Add(new student { name = \"王五\", age = 19 });\n",
    "\n",
    "var _num3 = _list.FirstOrDefault(n => n.age == 20);\n",
    "_num3.Dump();\n",
    "\n",
    "var _num4 = _list.FirstOrDefault(n => n.age == 21);\n",
    "_num4.Dump();  // null\n",
    "(_num4 is null).Dump();\n",
    "\n",
    "var _num5 = _list.FirstOrDefault(n => n.age == 21, new student { name = \"默认\", age = 20 });\n",
    "_num5.Dump();"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2020年01月01日, 2020年01月02日, 2020年01月03日, 2020年01月04日\r\n"
     ]
    }
   ],
   "source": [
    "List<DateTime> _list = new List<DateTime>();\n",
    "_list.Add(new DateTime(2020, 1, 1));\n",
    "_list.Add(new DateTime(2020, 1, 2));\n",
    "_list.Add(new DateTime(2020, 1, 3));\n",
    "_list.Add(new DateTime(2020, 1, 4));\n",
    "\n",
    "var _num6 = _list.Select(n => n.ToString(\"yyyy年MM月dd日\"));\n",
    "_num6.Dump();"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "polyglot-notebook"
  },
  "polyglot_notebook": {
   "kernelInfo": {
    "defaultKernelName": "csharp",
    "items": [
     {
      "aliases": [],
      "languageName": "csharp",
      "name": "csharp"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
